﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections;
using System.Security.Principal;

namespace SystemHelperLibrary.API.SystemExt
{
	public sealed class SystemHelp
	{
		private static SystemHelp m_inst = null;

		private SystemHelp()
		{
		}

		public static SystemHelp Instance
		{
			get
			{
				return m_inst ?? new SystemHelp();
			}
		}

		public const int MAX_COMPUTERNAME_LENGTH = 31;
		public const int INVALID_HANDLE = -1;

		public const int FILE_SHARE_READ = 0x00000001;
		public const int FILE_SHARE_WRITE = 0x00000002;
		public const int FILE_SHARE_DELETE = 0x00000004;

		public const int CREATE_NEW = 1;
		public const int CREATE_ALWAYS = 2;
		public const int OPEN_EXISTING = 3;
		public const int OPEN_ALWAYS = 4;
		public const int TRUNCATE_EXISTING = 5;

		public const uint GENERIC_READ = 0x80000000;
		public const int GENERIC_WRITE = 0x40000000;
		public const int GENERIC_EXECUTE = 0x20000000;
		public const int GENERIC_ALL = 0x10000000;

		public const int IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080;

		public const int ERROR_INSUFFICIENT_BUFFER = 122;

		static public readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(-2147483648);
		static public readonly IntPtr HKEY_CURRENT_USER = new IntPtr(-2147483647);
		static public readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(-2147483646);
		static public readonly IntPtr HKEY_USERS = new IntPtr(-2147483645);
		static public readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(-2147483644);
		static public readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(-2147483643);
		static public readonly IntPtr HKEY_DYN_DATA = new IntPtr(-2147483642);

		public const int KEY_READ = 0x20019;
		public const int KEY_WRITE = 0x20006;
		public const int KEY_QUERY_VALUE = 0x0001;
		public const int KEY_SET_VALUE = 0x0002;
		public const int KEY_WOW64_64KEY = 0x0100;
		public const int KEY_WOW64_32KEY = 0x0200;

		public const int REG_NONE = 0;
		public const int REG_SZ = 1;
		public const int REG_EXPAND_SZ = 2;
		public const int REG_BINARY = 3;
		public const int REG_DWORD = 4;
		public const int REG_DWORD_BIG_ENDIAN = 5;
		public const int REG_LINK = 6;
		public const int REG_MULTI_SZ = 7;
		public const int REG_RESOURCE_LIST = 8;
		public const int REG_FULL_RESOURCE_DESCRIPTOR = 9;
		public const int REG_RESOURCE_REQUIREMENTS_LIST = 10;
		public const int REG_QWORD = 11;

		public const int LOGON32_LOGON_INTERACTIVE = 2;
		public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 3;
		public const int LOGON32_LOGON_PROVIDER_DEFAULT = 0;

		public enum COMPUTER_NAME_FORMAT
		{
			ComputerNameNetBIOS,
			ComputerNameDnsHostname,
			ComputerNameDnsDomain,
			ComputerNameDnsFullyQualified,
			ComputerNamePhysicalNetBIOS,
			ComputerNamePhysicalDnsHostname,
			ComputerNamePhysicalDnsDomain,
			ComputerNamePhysicalDnsFullyQualified,
			ComputerNameMax
		}

		public enum DRIVE_TYPE
		{
			DRIVE_TYPE_UNDTERMINED = 0,
			DriveRootNotExist = 1,
			Removable = 2,
			FixedDisk = 3,
			Remote = 4,
			CDDVDROM = 5,
			RamDisk = 6
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct STARTUPINFO
		{
			public uint cb;
			public string lpReserved;
			public string lpDesktop;
			public string lpTitle;
			public uint dwX;
			public uint dwY;
			public uint dwXSize;
			public uint dwYSize;
			public uint dwXCountChars;
			public uint dwYCountChars;
			public uint dwFillAttribute;
			public uint dwFlags;
			public ushort wShowWindow;
			public ushort cbReserved2;
			public IntPtr lpReserved2;
			public IntPtr hStdInput;
			public IntPtr hStdOutput;
			public IntPtr hStdError;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct SYSTEM_INFO
		{
			public ushort wProcessorArchitecture;
			public ushort wReserved;
			public uint dwPageSize;
			public IntPtr lpMinimumApplicationAddress;
			public IntPtr lpMaximumApplicationAddress;
			public uint dwArchitectureProcessorMask;
			public uint dwNumberOfProcessors;
			public uint dwProcessorType;
			public uint dwAllocatingGranularity;
			public uint dwProcessorLevel;
			public uint dwProcessorRevision;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct SYSTEM_TIME
		{
			public uint wYEAR;
			public uint wMonth;
			public uint dayOfWeek;
			public uint Day;
			public uint Hour;
			public uint Minute;
			public uint Second;
			public uint Miliseconds;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct STORAGE_DEVICE_NUMBER
		{
			public DEVICE_TYPE DeviceType;
			public int DeviceNumber;
			public int PartitionNumber;
		}

		[Flags()]
		public enum DEVICE_TYPE
		{
			FILE_DEVICE_8042_PORT = 0x00000027,
			FILE_DEVICE_ACPI = 0x00000032,
			FILE_DEVICE_BATTERY = 0x00000029,
			FILE_DEVICE_BEEP = 0x00000001,
			FILE_DEVICE_BUS_EXTENDER = 0x0000002a,
			FILE_DEVICE_CD_ROM = 0x00000002,
			FILE_DEVICE_CD_ROM_FILE_SYSTEM = 0x00000003,
			FILE_DEVICE_CHANGER = 0x00000030,
			FILE_DEVICE_CONTROLLER = 0x00000004,
			FILE_DEVICE_DATALINK = 0x00000005,
			FILE_DEVICE_DFS = 0x00000006,
			FILE_DEVICE_DFS_FILE_SYSTEM = 0x00000035,
			FILE_DEVICE_DFS_VOLUME = 0x00000036,
			FILE_DEVICE_DISK = 0x00000007,
			FILE_DEVICE_DISK_FILE_SYSTEM = 0x00000008,
			FILE_DEVICE_DVD = 0x00000033,
			FILE_DEVICE_FILE_SYSTEM = 0x00000009,
			FILE_DEVICE_FIPS = 0x0000003a,
			FILE_DEVICE_FULLSCREEN_VIDEO = 0x00000034,
			FILE_DEVICE_INPORT_PORT = 0x0000000a,
			FILE_DEVICE_KEYBOARD = 0x0000000b,
			FILE_DEVICE_KS = 0x0000002f,
			FILE_DEVICE_KSEC = 0x00000039,
			FILE_DEVICE_MAILSLOT = 0x0000000c,
			FILE_DEVICE_MASS_STORAGE = 0x0000002d,
			FILE_DEVICE_MIDI_IN = 0x0000000d,
			FILE_DEVICE_MIDI_OUT = 0x0000000e,
			FILE_DEVICE_MODEM = 0x0000002b,
			FILE_DEVICE_MOUSE = 0x0000000f,
			FILE_DEVICE_MULTI_UNC_PROVIDER = 0x00000010,
			FILE_DEVICE_NAMED_PIPE = 0x00000011,
			FILE_DEVICE_NETWORK = 0x00000012,
			FILE_DEVICE_NETWORK_BROWSER = 0x00000013,
			FILE_DEVICE_NETWORK_FILE_SYSTEM = 0x00000014,
			FILE_DEVICE_NETWORK_REDIRECTOR = 0x00000028,
			FILE_DEVICE_NULL = 0x00000015,
			FILE_DEVICE_PARALLEL_PORT = 0x00000016,
			FILE_DEVICE_PHYSICAL_NETCARD = 0x00000017,
			FILE_DEVICE_PRINTER = 0x00000018,
			FILE_DEVICE_SCANNER = 0x00000019,
			FILE_DEVICE_SCREEN = 0x0000001c,
			FILE_DEVICE_SERENUM = 0x00000037,
			FILE_DEVICE_SERIAL_MOUSE_PORT = 0x0000001a,
			FILE_DEVICE_SERIAL_PORT = 0x0000001b,
			FILE_DEVICE_SMARTCARD = 0x00000031,
			FILE_DEVICE_SMB = 0x0000002e,
			FILE_DEVICE_SOUND = 0x0000001d,
			FILE_DEVICE_STREAMS = 0x0000001e,
			FILE_DEVICE_TAPE = 0x0000001f,
			FILE_DEVICE_TAPE_FILE_SYSTEM = 0x00000020,
			FILE_DEVICE_TERMSRV = 0x00000038,
			FILE_DEVICE_TRANSPORT = 0x00000021,
			FILE_DEVICE_UNKNOWN = 0x00000022,
			FILE_DEVICE_VDM = 0x0000002c,
			FILE_DEVICE_VIDEO = 0x00000023,
			FILE_DEVICE_VIRTUAL_DISK = 0x00000024,
			FILE_DEVICE_WAVE_IN = 0x00000025,
			FILE_DEVICE_WAVE_OUT = 0x00000026
		}

		[StructLayout(LayoutKind.Sequential)]
		internal struct SECURITY_ATTRIBUTES
		{
			internal Int32 nLength;
			internal IntPtr lpSecurityDescriptor;
			internal bool bInheritHandle;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public struct DISPLAY_DEVICE
		{
			[MarshalAs(UnmanagedType.U4)]
			public int cb;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
			public string DeviceName;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
			public string DeviceString;
			[MarshalAs(UnmanagedType.U4)]
			public DisplayDeviceStateFlags StateFlags;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
			public string DeviceID;
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
			public string DeviceKey;
		}

		[Flags()]
		public enum DisplayDeviceStateFlags : int
		{
			/// <summary>The device is part of the desktop.</summary>
			AttachedToDesktop = 0x1,
			MultiDriver = 0x2,
			/// <summary>The device is part of the desktop.</summary>
			PrimaryDevice = 0x4,
			/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
			MirroringDriver = 0x8,
			/// <summary>The device is VGA compatible.</summary>
			VGACompatible = 0x16,
			/// <summary>The device is removable; it cannot be the primary display.</summary>
			Removable = 0x20,
			/// <summary>The device has more display modes than its output devices support.</summary>
			ModesPruned = 0x8000000,
			Remote = 0x4000000,
			Disconnect = 0x2000000
		}

		/// <summary>
		/// DnsHostnameToComputerName
		/// </summary>
		/// <param name="hostName"></param>
		/// <param name="buf"></param>
		/// <param name="bufSize">must be bufSize+1</param>
		/// <returns></returns>
		[DllImport("kernel32.dll")]
		internal static extern bool DnsHostnameToComputerName(string hostName, StringBuilder buf, int bufSize);

		/// <summary>
		/// ExpandEnviromentStrings
		/// </summary>
		/// <param name="source"></param>
		/// <param name="dest"></param>
		/// <param name="nSize"></param>
		/// <returns>0 if error</returns>
		[DllImport("kernel32.dll")]
		internal static extern uint ExpandEnvironmentStrings(string source, StringBuilder dest, int nSize);

		[DllImport("kernel32.dll")]
		internal static extern IntPtr GetEnvironmentStrings();

		[DllImport("kernel32.dll", EntryPoint = "GetEnvironmentStringsW")]
		[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringArrayMarshalerW))]
		internal static extern string[] GetEnvironmentStringsArr();

		[DllImport("kernel32.dll")]
		internal static extern bool FreeEnvironmentStrings(IntPtr lpszEnvironmentBlock);

		[DllImport("kernel32.dll")]
		internal static extern uint GetEnvironmentVariable(string varName, StringBuilder buff, int bufLen);

		[DllImport("kernel32.dll")]
		internal static extern bool SetEnvironmentVariable(string varName, string varValue);

		[DllImport("kernel32.dll")]
		internal static extern string GetCommandLine();

		[DllImport("kernel32.dll")]
		internal static extern bool GetComputerName(StringBuilder buff, ref int bufSize);

		[DllImport("kernel32.dll")]
		internal static extern bool GetComputerNameEx(COMPUTER_NAME_FORMAT format, StringBuilder buff, uint bufSize);

		[DllImport("kernel32.dll")]
		internal static extern bool SetComputerName(string CompName);

		[DllImport("kernel32.dll")]
		internal static extern uint GetCurrentDirectory(int bufSize, StringBuilder buff);

		[DllImport("kernel32.dll")]
		internal static extern uint GetDriveType(string rootPath);

		[DllImport("kernel32.dll")]
		internal static extern uint GetLogicalDrives();

		[DllImport("kernel32.dll")]
		internal static extern uint GetLogicalDriveStrings(uint bufLen, uint buff);

		[DllImport("kernel32.dll")]
		internal static extern uint GetStartupInfo(ref STARTUPINFO lpsi);

		[DllImport("kernel32.dll")]
		internal static extern void GetSystemInfo(ref SYSTEM_INFO lpSysInfo);

		[DllImport("kernel32.dll")]
		internal static extern void GetSystemTime(ref SYSTEM_TIME lpSysTyme);

		[DllImport("kernel32.dll")]
		internal static extern bool SetCurrentDirectory(string dir);

		[DllImport("kernel32.dll")]
		internal static extern bool SetVolumeInformation(string rootDir, string volumeName);

		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
		internal static extern IntPtr CreateFile(String lpFileName, uint dwDesiredAccess, uint dwShareMode,
												ref SECURITY_ATTRIBUTES lpSecurityAtt, uint dwCreate, uint dwFlagsAndAttr,
												IntPtr hTemplateFile);

		[DllImport("kernel32.dll", SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool CloseHandle(IntPtr hObject);

		[DllImport("kernel32.dll")]
		internal static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize,
													ref STORAGE_DEVICE_NUMBER lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);

		[DllImport("kernel32.dll")]
		internal static extern uint QueryDosDevice(string lpDeviceName, IntPtr lpTargetPath, uint ucchMax);
		[DllImport("kernel32.dll")]
		internal static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);

		[DllImport("user32.dll")]
		internal static extern bool CharToOem(string source, StringBuilder output);

		internal delegate bool EnumSystemCodePagesCallback(string lpCodePageStr);
		[DllImport("kernel32.dll")]
		internal static extern bool EnumSystemCodePages(EnumSystemCodePagesCallback callback, uint flags);

		internal delegate bool EnumSystemCodeLocalesCallback(string lpCodePageStr);
		[DllImport("kernel32.dll")]
		internal static extern bool EnumSystemLocales(EnumSystemCodeLocalesCallback callback, uint flags);

		[DllImport("user32.dll")]
		internal static extern bool IsCharAlpha(char ch);

		[DllImport("user32.dll")]
		internal static extern bool IsCharAlphaNumeric(char ch);

		[DllImport("user32.dll")]
		internal static extern bool OemToChar(string source, StringBuilder dest);

		[DllImport("kernel32.dll")]
		internal static extern int GetTickCount();

		internal delegate void TimerCallbackWin32(IntPtr hwnd, uint msg, uint idEvent, uint dwTime);

		[DllImport("user32.dll")]
		internal static extern uint SetTimer(IntPtr hwnd, uint timerId, uint interval, TimerCallbackWin32 callback);

		[DllImport("user32.dll")]
		internal static extern bool KillTimer(IntPtr hwnd, uint timerId);

		[DllImport("kernel32.dll")]
		internal static extern IntPtr GetCurrentProcess();

		[DllImport("kernel32.dll")]
		internal static extern bool TerminateProcess(IntPtr handle, uint exitCode);

		[DllImport("kernel32.dll")]
		internal static extern int GetCurrentProcessId();

		[DllImport("kernel32.dll")]
		internal static extern IntPtr GetCurrentThread();

		[DllImport("kernel32.dll")]
		internal static extern IntPtr GetCurrentThreadId();

		[DllImport("kernel32.dll")]
		internal static extern bool TerminateThread(IntPtr hThread, uint exitCode);

		[DllImport("kernel32.dll")]
		internal static extern int GetThreadPriority(IntPtr handle);

		[DllImport("kernel32.dll")]
		internal static extern IntPtr GetCurrentFiber();

		[Flags()]
		public enum KEY_MODIFIER : uint
		{
			None = 0,
			Alt = 1,
			Control = 2,
			Shift = 3,
			Win = 4
		}

		[DllImport("kernel32.dll")]
		internal static extern bool RegisterHotKey(IntPtr hwnd, int hotKeyId, KEY_MODIFIER uModif, uint virtKeyCode);

		[DllImport("kernel32.dll")]
		internal static extern bool UnregisterHotKey(IntPtr hwnd, int hotKeyId);

		[DllImport("kernel32.dll")]
		internal static extern void Sleep(int milsec);

		[StructLayout(LayoutKind.Sequential)]
		public class MEMORY_STATUSEX
		{
			public uint dwLength;
			public ulong dwMemoryLoad;
			public ulong dwTotalPhys;
			public ulong dwAvaliablePhys;
			public ulong dwTotalPageFile;
			public ulong dwAvailablePageFile;
			public ulong dwTotalVirtual;
			public ulong dwAvaliableVirtual;
			public ulong AvailExtendedVirtual;

			public MEMORY_STATUSEX()
			{
				dwLength = (uint)Marshal.SizeOf(typeof(MEMORY_STATUSEX));
			}
		}

		[DllImport("Kernel32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool GlobalMemoryStatusEx([In, Out] MEMORY_STATUSEX ms);

		[DllImport("Advapi32.dll", EntryPoint = "RegOpenKeyExW", CharSet = CharSet.Unicode)]
		internal static extern int RegOpenKeyEx(IntPtr hKey, [In] string lpSubKey, int ulOptions, int samDesired, out IntPtr phkResult);

		[DllImport("Advapi32.dll", EntryPoint = "RegQueryValueExW", CharSet = CharSet.Unicode)]
		internal static extern int RegQueryValueEx(IntPtr hKey, [In] string lpValueName, IntPtr lpReserved, out int lpType, [Out] byte[] lpData, ref int lpcbData);

		[DllImport("advapi32.dll")]
		internal static extern int RegCloseKey(IntPtr hKey);

		[DllImport("user32.dll")]
		internal static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

		internal delegate bool EnumDesktopWindowsHandler(IntPtr hWnd, int lParam);
		[DllImport("user32.dll")]
		internal static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDesktopWindowsHandler lpfn, IntPtr lParam);

		[DllImport("user32.dll", EntryPoint = "GetWindowText", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);

		public delegate bool EnumDesktopsDelegate(string desktop, IntPtr lParam);
		[DllImport("user32.dll")]
		internal static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopsDelegate lpEnumFunc, IntPtr lParam);

		[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
		public struct DEVMODE
		{
			public const int CCHDEVICENAME = 32;
			public const int CCHFORMNAME = 32;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
			[System.Runtime.InteropServices.FieldOffset(0)]
			public string dmDeviceName;
			[System.Runtime.InteropServices.FieldOffset(32)]
			public Int16 dmSpecVersion;
			[System.Runtime.InteropServices.FieldOffset(34)]
			public Int16 dmDriverVersion;
			[System.Runtime.InteropServices.FieldOffset(36)]
			public Int16 dmSize;
			[System.Runtime.InteropServices.FieldOffset(38)]
			public Int16 dmDriverExtra;
			[System.Runtime.InteropServices.FieldOffset(40)]
			public DM dmFields;
			[System.Runtime.InteropServices.FieldOffset(44)]
			Int16 dmOrientation;
			[System.Runtime.InteropServices.FieldOffset(46)]
			Int16 dmPaperSize;
			[System.Runtime.InteropServices.FieldOffset(48)]
			Int16 dmPaperLength;
			[System.Runtime.InteropServices.FieldOffset(50)]
			Int16 dmPaperWidth;
			[System.Runtime.InteropServices.FieldOffset(52)]
			Int16 dmScale;
			[System.Runtime.InteropServices.FieldOffset(54)]
			Int16 dmCopies;
			[System.Runtime.InteropServices.FieldOffset(56)]
			Int16 dmDefaultSource;
			[System.Runtime.InteropServices.FieldOffset(58)]
			Int16 dmPrintQuality;
			[System.Runtime.InteropServices.FieldOffset(44)]
			public POINTL dmPosition;
			[System.Runtime.InteropServices.FieldOffset(52)]
			public Int32 dmDisplayOrientation;
			[System.Runtime.InteropServices.FieldOffset(56)]
			public Int32 dmDisplayFixedOutput;
			[System.Runtime.InteropServices.FieldOffset(60)]
			public short dmColor;
			[System.Runtime.InteropServices.FieldOffset(62)]
			public short dmDuplex;
			[System.Runtime.InteropServices.FieldOffset(64)]
			public short dmYResolution;
			[System.Runtime.InteropServices.FieldOffset(66)]
			public short dmTTOption;
			[System.Runtime.InteropServices.FieldOffset(68)]
			public short dmCollate;
			[System.Runtime.InteropServices.FieldOffset(72)]
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
			public string dmFormName;
			[System.Runtime.InteropServices.FieldOffset(102)]
			public Int16 dmLogPixels;
			[System.Runtime.InteropServices.FieldOffset(104)]
			public Int32 dmBitsPerPel;
			[System.Runtime.InteropServices.FieldOffset(108)]
			public Int32 dmPelsWidth;
			[System.Runtime.InteropServices.FieldOffset(112)]
			public Int32 dmPelsHeight;
			[System.Runtime.InteropServices.FieldOffset(116)]
			public Int32 dmDisplayFlags;
			[System.Runtime.InteropServices.FieldOffset(116)]
			public Int32 dmNup;
			[System.Runtime.InteropServices.FieldOffset(120)]
			public Int32 dmDisplayFrequency;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
		public struct POINTL
		{
			public Int32 x;
			public Int32 y;
		}

		[Flags()]
		public enum DM : int
		{
			Orientation = 0x1,
			PaperSize = 0x2,
			PaperLength = 0x4,
			PaperWidth = 0x8,
			Scale = 0x10,
			Position = 0x20,
			NUP = 0x40,
			DisplayOrientation = 0x80,
			Copies = 0x100,
			DefaultSource = 0x200,
			PrintQuality = 0x400,
			Color = 0x800,
			Duplex = 0x1000,
			YResolution = 0x2000,
			TTOption = 0x4000,
			Collate = 0x8000,
			FormName = 0x10000,
			LogPixels = 0x20000,
			BitsPerPixel = 0x40000,
			PelsWidth = 0x80000,
			PelsHeight = 0x100000,
			DisplayFlags = 0x200000,
			DisplayFrequency = 0x400000,
			ICMMethod = 0x800000,
			ICMIntent = 0x1000000,
			MediaType = 0x2000000,
			DitherType = 0x4000000,
			PanningWidth = 0x8000000,
			PanningHeight = 0x10000000,
			DisplayFixedOutput = 0x20000000
		}

		[DllImport("user32.dll")]
		internal static extern bool EnumDisplaySettingsEx(string lpszDeviceName, uint iModeNum, out DEVMODE lpDevMode, uint dwFlags);

		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		internal static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);

		[DllImport("user32.dll")]
		[return: MarshalAs(UnmanagedType.Bool)]
		internal static extern bool SwapMouseButton([param: MarshalAs(UnmanagedType.Bool)] bool fSwap);

		[DllImport("user32.dll")]
		internal static extern bool SetForegroundWindow(IntPtr hWnd);

		[DllImport("advapi32.dll", SetLastError = true)]
		internal static extern int LogonUser(string lpUserName, string lpUserDomain, string lpPassword, int dwLogonType,
											int dwLogonProvider, ref IntPtr token);

		[DllImport("advapi32.dll", SetLastError = true)]
		internal static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr newToken);

		[DllImport("mscoree.dll", SetLastError = true)]
		internal static extern void GetCORSystemDirectory(StringBuilder sb, int buflen, ref int capacity);

		public static DRIVE_TYPE GetDriveTypeApi(string rootPath)
		{
			uint dt = GetDriveType(rootPath);
			return (DRIVE_TYPE)dt;
		}

		public static string GetEnvironmentStringsApi()
		{
			string rez = string.Empty;
			IntPtr pStr = GetEnvironmentStrings();

			unsafe
			{
				byte* pu = (byte*)pStr;
				while (*pu != 0)
				{
					while (*pu != 0)
					{
						rez += (char)*pu;
						pu++;
					}
					pu++;
					rez += '\n';
				}
			}
			FreeEnvironmentStrings(pStr);

			return rez;
		}

		public static string[] GetEnvironmentStringsArrApi()
		{
			return GetEnvironmentStringsArr();
		}

		public static string GetEnvironmentVariableApi(string name)
		{
			int len = 260;
			StringBuilder sb = new StringBuilder(len);
			if (GetEnvironmentVariable(name, sb, len) == 0)
			{
				return string.Empty;
			}
			return sb.ToString();
		}

		public static bool SetEnvironmentVariableApi(string name, string val)
		{
			return SetEnvironmentVariable(name, val);
		}

		public static string[] GetLogicalDrivesApi()
		{
			uint rez = GetLogicalDrives();

			byte val = Convert.ToByte(rez);

			string drives = Marshal.PtrToStringAnsi(new IntPtr((int)rez));

			return new string[0];
		}

		public static string[] GetLogicalDriveStringsApi()
		{
			uint rez = GetLogicalDrives();

			byte val = Convert.ToByte(rez);

			return new string[0];
		}

		public static STARTUPINFO GetSturtupInfoApi()
		{
			STARTUPINFO info = new STARTUPINFO();
			GetStartupInfo(ref info);
			return info;
		}

		public static SYSTEM_INFO GetSystemInfoApi()
		{
			SYSTEM_INFO info = new SYSTEM_INFO();
			GetSystemInfo(ref info);
			return info;
		}

		public static SYSTEM_TIME GetSystemTimeApi()
		{
			SYSTEM_TIME info = new SYSTEM_TIME();
			GetSystemTime(ref info);
			return info;
		}

		public static string GetComputerNameApi()
		{
			int len = MAX_COMPUTERNAME_LENGTH + 1;
			StringBuilder sb = new StringBuilder(len);
			GetComputerName(sb, ref len);
			return sb.ToString();
		}

		public static bool SetComputerNameApi(string compName)
		{
			return SetComputerName(compName);
		}

		public static bool SetCurrentDirectoryApi(string dir)
		{
			return SetCurrentDirectory(dir);
		}

		public static bool SetVolumeNameApi(string Volume, string volumeName)
		{
			return SetVolumeInformation(Volume, volumeName);
		}

		public static string[] QueryDosDeviceApi()
		{
			// Allocate some memory to get a list of all system devices.
			// Start with a small size and dynamically give more space until we have enough room.
			int returnSize = 0;
			int maxSize = 100;
			string allDevices = null;
			IntPtr mem;
			string[] retval = null;

			while (returnSize == 0)
			{
				mem = Marshal.AllocHGlobal(maxSize);
				if (mem != IntPtr.Zero)
				{
					// mem points to memory that needs freeing
					try
					{
						returnSize = (int)QueryDosDevice(null, mem, (uint)maxSize);
						if (returnSize != 0)
						{
							allDevices = Marshal.PtrToStringAnsi(mem, returnSize);
							retval = allDevices.Split('\0');
							break;
							// not really needed, but makes it more clear...
						}
						else if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
						{
							maxSize *= 10;
						}
						else
						{
							//Marshal.ThrowExceptionForHR();
						}
					}
					finally
					{
						Marshal.FreeHGlobal(mem);
					}
				}
				else
				{
					throw new OutOfMemoryException();
				}
			}
			return retval;
		}

		public static string GetRealPath(string path)
		{
			string realPath;
			StringBuilder pathInformation = new StringBuilder(250);

			// Get the drive letter of the 
			string driveLetter = System.IO.Path.GetPathRoot(path).Replace("\\", "");
			QueryDosDevice(driveLetter, pathInformation, 250);

			// If drive is substed, the result will be in the format of "\??\C:\RealPath\".
			if (pathInformation.ToString().Contains("\\??\\"))
			{
				// Strip the \??\ prefix.
				string realRoot = pathInformation.ToString().Remove(0, 4);

				//Combine the paths.
				realPath = System.IO.Path.Combine(realRoot,
												path.Replace(System.IO.Path.GetPathRoot(path), ""));
			}
			else
			{
				realPath = path;
			}
			return realPath;
		}

		public static void RemoveUsb(string driveLetter)
		{
			SECURITY_ATTRIBUTES secAttr = new SECURITY_ATTRIBUTES();
			string volumeAccessPath = string.Format("\\\\.\\{0}", driveLetter.Replace("\\", ""));
			//TODO: check function win32 CreateFile
			IntPtr handle = CreateFile(volumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, ref secAttr, OPEN_EXISTING, 0, IntPtr.Zero);

			if (handle.ToInt32() == INVALID_HANDLE)
				return;


			STORAGE_DEVICE_NUMBER sdn = new STORAGE_DEVICE_NUMBER();
			uint lpBytesReturned;
			int devNumb = -2;

			bool rez = DeviceIoControl(handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, IntPtr.Zero, 0, ref sdn, (uint)Marshal.SizeOf(typeof(STORAGE_DEVICE_NUMBER)),
									out lpBytesReturned, IntPtr.Zero);
			if (rez)
			{
				devNumb = sdn.DeviceNumber;
			}

			CloseHandle(handle);

			if (devNumb == -1)
			{
				return;
			}

			DRIVE_TYPE dt = (DRIVE_TYPE)GetDriveType(driveLetter);

			int len = 260 + 1;
			StringBuilder sb = new StringBuilder(len);
			uint funRes = QueryDosDevice(driveLetter, sb, len);
			if (funRes != 0) return;
		}

		public static string ConvertStringToOem(string source)
		{
			StringBuilder sb = new StringBuilder(source.Length + 1);
			if (CharToOem(source, sb))
			{
				return sb.ToString();
			}
			return string.Empty;
		}

		public bool EnumCodePagesApi()
		{
			EnumSystemCodePagesCallback del = new EnumSystemCodePagesCallback(CalFun);
			bool result = EnumSystemCodePages(del, 1);
			return result;
		}

		private bool CalFun(string codePage)
		{
			return string.IsNullOrEmpty(codePage);
		}

		public bool EnumCodeLocalseApi()
		{
			EnumSystemCodeLocalesCallback del = new EnumSystemCodeLocalesCallback(CalLocaleFun);
			bool result = EnumSystemLocales(del, 0);
			return result;
		}

		private bool CalLocaleFun(string locale)
		{
			return string.IsNullOrEmpty(locale);
		}

		public static bool IsCharAlphaApi(char ch)
		{
			return IsCharAlpha(ch);
		}

		public static bool IsCharAlphaNumericApi(char ch)
		{
			return IsCharAlphaNumeric(ch);
		}

		public static string OemToCharApi(string str)
		{
			dynamic sb = new StringBuilder();
			OemToChar(str, sb);
			return sb.ToString();
		}

		public static int GetTickCountApi()
		{
			return GetTickCount();
		}

		public uint CreateTimerApi(IntPtr hwnd, uint interval)
		{
			TimerCallbackWin32 cdel = new TimerCallbackWin32(TimerCallbackFun);
			uint timerId = 0;
			uint timerRet = 0;
			if ((timerRet = SetTimer(hwnd, timerId, interval, cdel)) != 0)
			{
				if (hwnd == IntPtr.Zero)
					return timerId;
				return timerRet;
			}
			return 0;
		}

		public bool DeleteTimerApi(IntPtr hwnd, uint timerId)
		{
			return KillTimer(hwnd, timerId);
		}

		private void TimerCallbackFun(IntPtr hwnd, uint msg, uint idEvent, uint dwTime)
		{
			uint msgd = msg;
		}

		public static void SleepApi(int miliseconds)
		{
			Sleep(miliseconds);
		}

		public static IntPtr GetCurrentProcessApi()
		{
			return GetCurrentProcess();
		}

		public static bool TerminateProcessApi(IntPtr handle, uint exit)
		{
			return TerminateProcess(handle, exit);
		}

		public static IntPtr GetCurrentThreadApi()
		{
			return GetCurrentThread();
		}

		public static IntPtr GetCurrentThreadIdApi()
		{
			return GetCurrentThreadId();
		}

		public static bool TerminateThreadApi(IntPtr hThread)
		{
			return TerminateThread(hThread, 0);
		}

		public static int GetThreadPriorityApi(IntPtr hThread)
		{
			return GetThreadPriority(hThread);
		}

		public static MEMORY_STATUSEX GetMemoryStatusExApi()
		{
			MEMORY_STATUSEX ms = new MEMORY_STATUSEX();
			if (GlobalMemoryStatusEx(ms))
			{
				return ms;
			}
			return null;
		}

		public static object RegQueryValue(IntPtr key, string value)
		{
			return RegQueryValue(key, value, null);
		}

		public static object RegQueryValue(IntPtr key, string value, object defaultValue)
		{
			int error, type = 0, dataLength = 0xfde8;
			int returnLength = dataLength;
			byte[] data = new byte[dataLength];
			while ((error = RegQueryValueEx(key, value, IntPtr.Zero, out type, data, ref returnLength)) == 0xea)
			{
				dataLength *= 2;
				returnLength = dataLength;
				data = new byte[dataLength];
			}
			if (error == 2)
				return defaultValue; // value doesn't exist
			if (error != 0)
				throw new System.ComponentModel.Win32Exception(error);

			switch (type)
			{
				case REG_NONE:
				case REG_BINARY:
					return data;
				case REG_DWORD:
					return (((data[0] | (data[1] << 8)) | (data[2] << 16)) | (data[3] << 24));
				case REG_DWORD_BIG_ENDIAN:
					return (((data[3] | (data[2] << 8)) | (data[1] << 16)) | (data[0] << 24));
				case REG_QWORD:
					{
						uint numLow = (uint)(((data[0] | (data[1] << 8)) | (data[2] << 16)) | (data[3] << 24));
						uint numHigh = (uint)(((data[4] | (data[5] << 8)) | (data[6] << 16)) | (data[7] << 24));
						return (long)(((ulong)numHigh << 32) | (ulong)numLow);
					}
				case REG_SZ:
					return Encoding.Unicode.GetString(data, 0, returnLength);
				case REG_EXPAND_SZ:
					return Environment.ExpandEnvironmentVariables(Encoding.Unicode.GetString(data, 0, returnLength));
				case REG_MULTI_SZ:
					{
						var strings = new List<string>();
						string packed = Encoding.Unicode.GetString(data, 0, returnLength);
						int start = 0;
						int end = packed.IndexOf('\0', start);
						while (end > start)
						{
							strings.Add(packed.Substring(start, end - start));
							start = end + 1;
							end = packed.IndexOf('\0', start);
						}
						return strings.ToArray();
					}
				default:
					throw new NotSupportedException();
			}
		}

		public static int CloseRegKeyApi(IntPtr key)
		{
			return RegCloseKey(key);
		}

		public List<DISPLAY_DEVICE> ListDisplayDevices()
		{
			List<DISPLAY_DEVICE> list = new List<DISPLAY_DEVICE>();

			DISPLAY_DEVICE d = new DISPLAY_DEVICE();
			d.cb = Marshal.SizeOf(d);
			try
			{
				for (uint id = 0; EnumDisplayDevices(null, id, ref d, 0); id++)
				{
					list.Add(d);
					d.cb = Marshal.SizeOf(d);
				}
			}
			catch (Exception)
			{
			}

			return list;
		}

		private ArrayList m_TitleList;
		public string[] GetDesktopWindowsCaptions()
		{
			if (m_TitleList == null)
				m_TitleList = new ArrayList();
			m_TitleList.Clear();
			EnumDesktopWindowsHandler enumfunc = new EnumDesktopWindowsHandler(EnumDesktopWindowsHandlerFun);
			IntPtr hDesktop = IntPtr.Zero; // current desktop

			if (EnumDesktopWindows(hDesktop, enumfunc, IntPtr.Zero))
			{
				string[] titles = new string[m_TitleList.Count];
				m_TitleList.CopyTo(titles);
				return titles;
			}
			else
			{
				// Get the last Win32 error code
				int errorCode = Marshal.GetLastWin32Error();
				string errorMessage = String.Format("EnumDesktopWindows failed with code {0}.", errorCode);
				throw new Exception(errorMessage);
			}
		}

		private bool EnumDesktopWindowsHandlerFun(IntPtr hWnd, int lParam)
		{
			string title = GetWindowText(hWnd);
			if (!string.IsNullOrEmpty(title))
				m_TitleList.Add(title);
			return true;
		}

		public string GetWindowText(IntPtr hWnd)
		{
			StringBuilder title = new StringBuilder(260);
			int titleLength = GetWindowText(hWnd, title, title.Capacity + 1);
			title.Length = titleLength;
			return title.ToString();
		}

		private List<string> m_desktops;

		public List<string> GetDesktops()
		{
			m_desktops = m_desktops ?? new List<string>();
			m_desktops.Clear();

			EnumDesktopsDelegate del = new EnumDesktopsDelegate(EnumDesktopsDelegateFun);

			if (EnumDesktops(IntPtr.Zero, del, IntPtr.Zero))
			{
				return m_desktops;
			}

			return null;
		}

		private bool EnumDesktopsDelegateFun(string desktop, IntPtr pPtr)
		{
			if (!string.IsNullOrEmpty(desktop))
				m_desktops.Add(desktop);
			return true;
		}

		public static DEVMODE GetDisplaySettingsApi(string devName)
		{
			DEVMODE mode = new DEVMODE();
			mode.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
			if (EnumDisplaySettingsEx(devName, 0, out mode, 0))
			{
				return mode;
			}
			return new DEVMODE();
		}

		public static void ChangeWallpaper(string wallpaperPath)
		{
			if (!System.IO.File.Exists(wallpaperPath))
				return;
			SystemParametersInfo(20, 0, wallpaperPath, 0x1 | 0x2);
		}

		public static void SwapMouseButtonsApi(bool makeRightButtonPrimary)
		{
			SwapMouseButton(makeRightButtonPrimary);
		}

		public static void OpenCurrentWindow()
		{
			//System.Windows.MessageBox.Show("Application already running");
			System.Diagnostics.Process current = System.Diagnostics.Process.GetCurrentProcess();
			foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcessesByName(current.ProcessName))
			{
				if (process.Id != current.Id)
				{
					SetForegroundWindow(process.MainWindowHandle);
					break;
				}
			}


		}

		public static void ProgrammingImpersonation(string username, string password, string domain)
		{
			WindowsIdentity wi = WindowsIdentity.GetCurrent();
			WindowsImpersonationContext impContext = null;

			try
			{
				WindowsIdentity newIdentity = null;
				IntPtr hToken = IntPtr.Zero;
				IntPtr hTokenDuplicate = IntPtr.Zero;

				if (LogonUser(username, domain, password, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_LOGON_PROVIDER_DEFAULT,
							ref hToken) != 0)
				{
					if (DuplicateToken(hToken, 2, ref hTokenDuplicate) != 0)
					{
						newIdentity = new WindowsIdentity(hTokenDuplicate);
						impContext = newIdentity.Impersonate();
					}
				}
			}
			catch (Exception)
			{
			}

			finally
			{
				//Return back impersonation
				WindowsIdentity curretIdentity = WindowsIdentity.GetCurrent();
				if (impContext != null)
					impContext.Undo();
			}
		}

		public static string GetNETFrameworkPath()
		{
			int capacity =260;
			StringBuilder sb = new StringBuilder(capacity);
			int realSize = 0;
			GetCORSystemDirectory(sb, capacity, ref realSize);
			return sb.ToString();
		}
	}

	public class StringArrayMarshalerW : ICustomMarshaler
	{
		static ICustomMarshaler GetInstance(string cookie)
		{ return new StringArrayMarshalerW(); }

		public void CleanUpManagedData(object ManagedObj) { }
		public void CleanUpNativeData(IntPtr pNativeData) { }
		public int GetNativeDataSize()
		{ throw new NotSupportedException(); }
		public IntPtr MarshalManagedToNative(object ManagedObj)
		{ throw new NotSupportedException(); }

		public unsafe object MarshalNativeToManaged(IntPtr pNativeData)
		{
			var strings = new List<string>();
			char* start = (char*)pNativeData;
			while (*start != '\0')
			{
				string newString = new string(start);
				strings.Add(newString);
				start += newString.Length + 1;
			}
			return strings.ToArray();
		}
	}

	public class ConsoleHelper
	{
		private ConsoleHelper()
		{
		}

		public const int STD_OUTPUT_HANDLE = -11;
		public const int STD_INPUT_HANDLE = -10;
		public const int STD_ERROR_HANDLE = -12;
		public const char WHITE_SPACE = ' ';

		[StructLayout(LayoutKind.Explicit)]
		public struct CONSOLE_SCREEN_BUFFER_INFO
		{
			[FieldOffset(18)]
			public COORD dwMaximumWindowSize;
			[FieldOffset(10)]
			public SMALL_RECT srWindow;
			[FieldOffset(8)]
			public ushort wAttributes;
			[FieldOffset(4)]
			public COORD dwCursorPosition;
			[FieldOffset(0)]
			public COORD dwSize;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct COORD
		{
			public short X;
			public short Y;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct SMALL_RECT
		{
			public short Left;
			public short Top;
			public short Right;
			public short Bottom;
		}


		[DllImport("Kernel32.dll")]
		internal static extern IntPtr GetStdHandle(int nStdHandle);

		[DllImport("Kernel32.dll")]
		internal static extern int GetConsoleScreenBufferInfo(IntPtr hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);

		[DllImport("Kernel32.dll")]
		internal static extern int FillConsoleOutputCharacter(IntPtr hConsoleOutput, char cCharacter, uint nLength,
															COORD dwWriteCoord, out uint lpNumberOfCharsWritten);

		[DllImport("Kernel32.dll")]
		internal static extern int SetConsoleCursorPosition(IntPtr hConsoleOutput, COORD dwCursorPosition);

		public static void AuthenticateUser()
		{
			Console.WriteLine("Please enter your password:");
			Console.Write("> "); // Two characters right

			string input = Console.ReadLine();

			while (input != "MyPassword")
			{
				COORD location = new COORD();
				// The third character
				location.X = 2;
				// The second line
				location.Y = 1;
				ClearConsoleScreen(location);
				input = Console.ReadLine();
			}

			// User authenticated
			Console.WriteLine("Authenticated!");
		}

		public static void ClearConsoleScreen()
		{
			// Getting the console output device handle
			IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);

			// Getting console screen buffer info
			CONSOLE_SCREEN_BUFFER_INFO info;
			GetConsoleScreenBufferInfo(handle, out info);

			// Discovering console screen buffer info
			Console.WriteLine("Console Buffer Info:");
			Console.WriteLine("--------------------");
			Console.WriteLine("Cursor Position:");
			Console.WriteLine("t{0}, {1}", info.dwCursorPosition.X, info.dwCursorPosition.Y);
			// Is this information right?
			Console.WriteLine("Maximum Window Size:");
			Console.WriteLine("t{0}, {1}", info.dwMaximumWindowSize.X, info.dwMaximumWindowSize.Y);

			// Is this information right?
			Console.WriteLine("Screen Buffer Size:");
			Console.WriteLine("t{0}, {1}", info.dwSize.X, info.dwSize.Y);
			Console.WriteLine("Screen Buffer Bounds:");
			Console.WriteLine("t{0}, {1}, {2}, {3}",
			 info.srWindow.Left, info.srWindow.Top,
			info.srWindow.Right, info.srWindow.Bottom);
			Console.WriteLine("--------------------");

			// Location of which to begin clearing
			COORD location = new COORD();
			location.X = 0;
			location.Y = 0;
			// What about clearing starting from
			// the second line
			// location.Y = 1;

			// The number of written characters
			uint numChars;

			FillConsoleOutputCharacter(handle, WHITE_SPACE, (uint)(info.dwSize.X * info.dwSize.Y), location, out numChars);

			// The new cursor location
			COORD cursorLocation = new COORD()
			{
				X = 0,
				Y = 0
			};

			SetConsoleCursorPosition(handle, cursorLocation);
		}

		public static void ClearConsoleScreen(COORD location)
		{
			// Getting the console output device handle
			IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);

			// Getting console screen buffer info
			CONSOLE_SCREEN_BUFFER_INFO info;
			GetConsoleScreenBufferInfo(handle, out info);

			// The number of written characters
			uint numChars;

			FillConsoleOutputCharacter(handle, WHITE_SPACE,
			(uint)(info.dwSize.X * info.dwSize.Y),
			location, out numChars);

			SetConsoleCursorPosition(handle, location);
		}

	}
}
